﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Xml.Linq;
using FBEntities.FBObjects;
using FBEntities.FBObjects.User;
using Newtonsoft.Json.Linq;
using XDAFacebook;
using XFControls.Utils;
using System.Text.RegularExpressions;

namespace FBEntities
{
    public class FBDataSource
    {
        public FBDataSource(string key)
        {
            FBParseUtilities.authKey = key;

            Me = FBCache.GetMe();
        }

        public FBPerson Me { get; set; }
    }

    public class FBBatch
    {
        public List<string> Results;
        public FBBatch(string json)
        {
            Results = new List<string>();

            var array = JArray.Parse(json);
            foreach (var res in array)
            {
                if (res["body"] == null) continue;

                string body = Regex.Unescape(res["body"].ToString()).Trim('\"');
                //string body = res["body"].ToString().Replace("\\\\", "\\").Trim('\"');
                body = body.Replace("\\n", "\n");
                Results.Add(body);
            }
        }
    }

    public static class FBCache
    {
        private static XDocument fbData;

        private static readonly string path = FBParseUtilities.CurDir + "\\data.xfd";
        private static readonly string meUrl = "https://graph." + Settings.Domain + ".com/me?" + authKey;

        internal static XDocument FbData
        {
            get
            {
                if (fbData == null)
                {
                    try
                    {
                        fbData = XDocument.Load(path);
                    }
                    catch (Exception)
                    {
                        fbData = new XDocument(
                            new XDeclaration("1.0", "utf-8", "yes"),
                            new XElement("cacheData"));
                    }
                }
                return fbData;
            }
        }

        private static string authKey
        {
            get { return FBParseUtilities.authKey; }
        }

        private static bool canCache()
        {
            if (!File.Exists(path))
            {
                var doc = new XDocument(
                    new XDeclaration("1.0", "utf-8", "yes"),
                    new XElement("cacheData"));

                doc.Save(path);
            }

            return true;
        }

        public static void Cache(string json, string id)
        {
            if (!canCache() || string.IsNullOrEmpty(json) || string.IsNullOrEmpty(id))
                return;

            XElement elm;
            if ((elm = FbData.Root.Element(id)) != null)
            {
                AddDataToCache(json, elm);
            }
            else
                FbData.Root.Add(new XElement(id, json));
        }

        private static void AddDataToCache(string json, XElement elm)
        {
            var curVal = elm.Value;
            JObject curValJson = JObject.Parse(curVal);
            JObject newValJson = JObject.Parse(json);

            foreach (var item in newValJson)
            {
                if (curValJson[item.Key] != null)
                    curValJson[item.Key] = item.Value;
                else
                    curValJson.Add(item.Key, item.Value);
            }
            elm.SetValue(curValJson.ToString());
        }

        public static void RemoveCache(string id)
        {
            var linq = from m in FbData.Root.Descendants()
                       where m.Name == id
                       select m;

            if (linq.Count() > 0)
            {
                XElement meXml = linq.First();
                meXml.Remove();
            }

            SaveCache();
        }

        public static void SaveCache()
        {
            try
            {
                FbData.Save(path);
            }
            catch (IOException e)
            {
                if (e.Message.Contains("being used by another process"))
                {
                    Thread.Sleep(300);
                    SaveCache();
                }
            }
        }

        internal static FBPerson GetMe()
        {
            var wrapper = new WebDownloaderWrapper(meUrl);
            var html = wrapper.Download();
            var o = JObject.Parse(html);

            var ret = new FBPerson();
            ret.Parse(o);

            return ret;
        }

        internal static string GetCache(string key)
        {
            if (!canCache() || string.IsNullOrEmpty(key))
                return "";

            XElement elm;
            return (elm = FbData.Root.Element(key)) != null ? elm.Value : "";
        }
    }
}